package com.chenu.gamscriptman.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.chenu.gamscriptman.dao.NotifyDao;
import com.chenu.gamscriptman.domain.Notify;
import com.chenu.gamscriptman.domain.noindb.Message;
import com.chenu.gamscriptman.service.NotifyService;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author flyan
 * date 2019-12-26
 * @function 系统通知任务
 */
@CacheConfig(cacheNames = "notify")   /* 本类使用缓存名称：NOTIFY */
@Service("notifyService")
public class NotifyServiceImpl implements NotifyService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /* 请求通知服务的服务路由键 */
    public static final String SERVICE_ROUTING_KEY = "notify";

    /* 消息服务器的通知消息队列 */
    public static final String QUEUE = "gamscriptman.notifyservice.queue";

    /* 数据库数据是否被更新了 */
    public static boolean DbIsUpdate = true;

    /* redis模板，用于缓存和处理结果的暂存 */
    @Autowired
    private RedisTemplate jsonRedisTemplate;

    /* gson，用于处理json数据 */
    @Autowired
    private Gson gson;

    /* dao */
    @Autowired
    NotifyDao notifyDao;
    
    /* 任务能提供的所有功能索引号 */
    public static final int NOTIFY_LIST = 0;                  /* 得到所有通知信息 */
    public static final int NOTIFY_ADD_OR_EDIT_VIEW = 1;      /* 前往通知添加/编辑页面 */
    public static final int NOTIFY_ADD_OR_UPDATE = 2;         /* 通知添加或更新 */
    public static final int NOTIFY_REMOVE = 3;                /* 通知删除 */
    public static final int NOTIFY_COUNT = 4;                   /* 得到通知数量 */
    public static final int NOTIFY_IS_NEW = 5;                   /* 是否有新通知？ */

    /**
     * 处理客户端发来的消息，提供服务，所有的服务都需要在这里注册，并规范化
     * 服务完成后，返回一个包含处理结果的消息，这个消息将回发到最初需要服务的例程
     * @param message 客户端发来的消息
     * @return 包含处理结果的消息
     */
    @Override
    @RabbitListener(queues = QUEUE)
    public Message service(Message message) {
        Message rs = null;  /* 就是一个指针 */

        /* 看看通知想做什么？ */
        switch (message.getType()){
            case NOTIFY_LIST:                 /* 列出所有通知 */
                logger.debug("通知任务：NOTIFY_LIST...");
                rs = do_list(message);
                break;

            case NOTIFY_ADD_OR_EDIT_VIEW:     /* 需要前往通知添加或编辑页面 */
                logger.debug("通知任务：NOTIFY_ADD_OR_EDIT_VIEW...");
                rs = do_nocall(message);
                break;

            case NOTIFY_ADD_OR_UPDATE:        /* 添加或更新一个通知 */
                logger.debug("通知任务：NOTIFY_ADD_OR_UPDATE...");
                rs = do_nocall(message);
                break;

            case NOTIFY_REMOVE:               /* 删除一个通知 */
                logger.debug("通知任务：NOTIFY_REMOVE...");
                rs = do_remove(message);
                break;

            case NOTIFY_COUNT:               /* 得到通知数量 */
                logger.debug("通知任务：NOTIFY_COUNT...");
                rs = do_count(message);
                break;

            case NOTIFY_IS_NEW:               /* 是否有新通知? */
                logger.debug("通知任务：NOTIFY_IS_NEW...");
                rs = do_is_new(message);
                break;

            default:
                logger.warn("通知任务：你正在请求一个不存在的功能服务...");
                rs = do_nocall(message);
                break;
        }

        return rs;
    }

    private Message do_list(Message message) {
        /* 列出通知比较简单，直接将用户的所有通知给他就行，不需要判断太多 */
        List<Notify> list = notifyDao.selectList(
                new QueryWrapper<Notify>().
                eq("user_fk", message.getSource()));

        /* 返回结果，这个调用不可能失败 */
        return MessageServiceImpl.TaskFinish(
                message,
                (long) MessageServiceImpl.NOTIFY_TASK,
                Message.HANDLER_SUCCESS,
                gson.toJson(list)
        );
    }

    /* 处理消息删除 */
    @Transactional(propagation = Propagation.NESTED, isolation = Isolation.DEFAULT, readOnly = false)
    Message do_remove(Message message) {
        int rows = 0;

        try {       /* 处理删除调用 */
            Long id = Long.parseLong(message.getData());
            rows = notifyDao.deleteById(id);
            /* 失败 */
            if(rows <= 0){
                logger.warn("通知任务：do_remove 失败！，给出的通知id --> " + id);
            }
        } catch (Exception e){  /* 处理清空调用 */
            rows = notifyDao.delete(new UpdateWrapper<Notify>().
                    eq("user_fk", message.getSource()));
            /* 失败 */
            if(rows <= 0){
                logger.warn("通知任务：do_clear 失败！");
            }
        }

        /* 不管如何，都返回该用户的所有通知 */
        return do_list(message);
    }

    private Message do_count(Message message) {
        /* 简单到不行... */
        int count = countNotify();
        return MessageServiceImpl.TaskFinish(
                message,
                (long) MessageServiceImpl.NOTIFY_TASK,
                Message.HANDLER_SUCCESS,
                count + ""
        );
    }

    private Message do_is_new(Message message) {
        /* 数据库被更新了我们就认为有新通知，不太好，因为这是多用户系统，以后完善@TODO */
        int rt = countNotify() > 0 ? 1 : 0;
        return MessageServiceImpl.TaskFinish(
                message,
                (long) MessageServiceImpl.NOTIFY_TASK,
                Message.HANDLER_SUCCESS,
                rt + ""
        );
    }

    /* 不支持该服务调用 */
    private Message do_nocall(Message message) {
        return MessageServiceImpl.TaskFinish(
                message,
                (long) MessageServiceImpl.NOTIFY_TASK,
                Message.HANDLER_FAILURE,
                "通知任务：你请求了一个不存在的功能服务......"
        );
    }

    /* 通知一个用户 */
    @Override
    @Transactional(propagation = Propagation.NESTED, isolation = Isolation.DEFAULT, readOnly = false)
    public boolean notify(Long uid, String text) {
        DbIsUpdate = true;
        if(text.length() > Notify.TEXT_LENGTH) return false;  /* 8行 */
        notifyDao.insert(new Notify().setUserFK(uid).setText(text));
        return true;
    }

    @Override
    public Integer countNotify() {
        return notifyDao.selectCount(null);
    }

    @Override
    @CacheEvict(key = "#id")
    public int remove(Long id) {
        DbIsUpdate = true;
        return notifyDao.deleteById(id);
    }

    @Override
    public int save(Notify record) {
        DbIsUpdate = true;
        return notifyDao.insert(record);
    }

    @Override
    @Cacheable(
            key = "#id",                               /* 缓存key使用用户的id */
            cacheManager = "jsonRedisCacheManager",     /* 使用json缓存管理器 */
            unless = "#result == null"                  /* 当没查到时，不缓存 */
    )
    public Notify findById(Long id) {
        return notifyDao.selectById(id);
    }

    @Override
    @CachePut(key = "#record.id")
    public int update(Notify record) {
        DbIsUpdate = true;
        return notifyDao.updateById(record);
    }

    @Override
    public int saveOrUpdate(Notify record) {
        DbIsUpdate = true;
        int rows = 0;
        // 根据是否有id决定是添加还是更新
        if(record.getId() == null){
            rows = save(record);
        } else {
            rows = update(record);
        }
        return rows;
    }
}
